-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: atchops_rsa_generate #409
Conversation
I have reached a blocker... Right now, MbedTLS only supports writing PKCS#1 formatted RSA 2048 private keys. This is what a PKCS 1 private key looks like (ASN.1 decoded). Link However, the goal of This is what a PKCS#8 formatted private key looks like (ASN.1 decoded). Link Currently, our Dart client writes PKCS#8 formatted keys. I did some research and came across this raised issue that is still open, which addresses the issue that PKCS#8 formatted private keys can be parsed, but not written. There was even a PR opened to implement PKCS#8 writing, but was never merged. The PR was opened in 2019. So in summary, writing PKCS#8 formatted RSA-2048 private keys is a known issue, which has a fix to it, but hasn't been merged yet by the MbedTLS team. There are two possible things to do here:
|
https://gist.github.com/JeremyTubongbanua/bc88bc7a818f7e5176d28a1975661e8f I got some progress in adding the proper PKCS#8 headers to the key, but not quite there yet |
We could also integrate an open source parser into |
MbedTLS comes with their own ASN.1 Parser that we currently use, if that's what you're referring to. So I don't think we have to develop any parsers ourselves (please let me know if I am misunderstanding). |
This is the hack that I produced: I hard coded the PKCS 8 headers to the key. Then simply copy and pasted the PKCS#1 key since the PKCS#1 is a subset of the entire PKCS#8 key. // PrivateKeyInfo SEQUENCE (3 elements)
private_key_pkcs8[0] = 0x30; // constructed sequence tag
private_key_pkcs8[1] = 0x82; // 8 --> 1000 0000 (1 in MSB means that it is long form) and 2 --> 0010 0000 (the next 2
// bytes are the length of data)
private_key_pkcs8[2] = (unsigned char)((private_key_pkcs8_size >> 8) & 0xFF);
private_key_pkcs8[3] = (unsigned char)(private_key_pkcs8_size & 0xFF);
// version INTEGER 0
private_key_pkcs8[4] = 0x02; // integer tag
private_key_pkcs8[5] = 0x01; // length of data
private_key_pkcs8[6] = 0x00; // data
// private key algorithm identifier
private_key_pkcs8[7] = 0x30; // constructed sequence tag
private_key_pkcs8[8] = 0x0D; // there are 2 elements in the sequence
private_key_pkcs8[9] = 0x06;
private_key_pkcs8[10] = 0x09;
private_key_pkcs8[11] = 0x2A;
private_key_pkcs8[12] = 0x86;
private_key_pkcs8[13] = 0x48;
private_key_pkcs8[14] = 0x86;
private_key_pkcs8[15] = 0xF7;
private_key_pkcs8[16] = 0x0D;
private_key_pkcs8[17] = 0x01;
private_key_pkcs8[18] = 0x01;
private_key_pkcs8[19] = 0x01;
private_key_pkcs8[20] = 0x05;
private_key_pkcs8[21] = 0x00;
// PrivateKey OCTET STRING
private_key_pkcs8[22] = 0x04; // octet string tag
private_key_pkcs8[23] = 0x82; // 8 --> 1000 0000 (1 in MSB means that it is long form) and 2 --> 0010 0000 (the next 2
// bytes are the length of data)
private_key_pkcs8[24] = (unsigned char)((private_key_non_base64_len >> 8) & 0xFF); // length of data
private_key_pkcs8[25] = (unsigned char)(private_key_non_base64_len & 0xFF); // length of data |
This is the unit test that successfully passes: atchops_rsa_key_public_key public_key;
atchops_rsa_key_public_key_init(&public_key);
atchops_rsa_key_private_key private_key;
atchops_rsa_key_private_key_init(&private_key);
const size_t ciphertext_size = 256;
unsigned char ciphertext[ciphertext_size];
memset(ciphertext, 0, sizeof(unsigned char) * ciphertext_size);
const size_t plaintext_size = 256;
unsigned char plaintext[plaintext_size];
memset(plaintext, 0, sizeof(unsigned char) * plaintext_size);
if ((ret = atchops_rsa_key_generate(&public_key, &private_key)) != 0) {
atlogger_log("test_rsa_generate", ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to generate RSA key pair\n");
goto exit;
}
// log the public key
if (atchops_rsa_key_is_public_key_populated(&public_key)) {
atlogger_log("test_rsa_generate", ATLOGGER_LOGGING_LEVEL_INFO, "Public Key:\n");
atlogger_log("test_rsa_generate", ATLOGGER_LOGGING_LEVEL_INFO, "N: ");
for (size_t i = 0; i < public_key.n.len; i++) {
printf("%02x ", public_key.n.value[i]);
}
printf("\n");
atlogger_log("test_rsa_generate", ATLOGGER_LOGGING_LEVEL_INFO, "E: ");
for (size_t i = 0; i < public_key.e.len; i++) {
printf("%02x ", public_key.e.value[i]);
}
printf("\n");
} else {
atlogger_log("test_rsa_generate", ATLOGGER_LOGGING_LEVEL_ERROR, "Public key is not populated\n");
goto exit;
}
// log the private key
if (atchops_rsa_key_is_private_key_populated(&private_key)) {
atlogger_log("test_rsa_generate", ATLOGGER_LOGGING_LEVEL_INFO, "Private Key:\n");
atlogger_log("test_rsa_generate", ATLOGGER_LOGGING_LEVEL_INFO, "N: ");
for (size_t i = 0; i < private_key.n.len; i++) {
printf("%02x ", private_key.n.value[i]);
}
printf("\n");
atlogger_log("test_rsa_generate", ATLOGGER_LOGGING_LEVEL_INFO, "E: ");
for (size_t i = 0; i < private_key.e.len; i++) {
printf("%02x ", private_key.e.value[i]);
}
printf("\n");
atlogger_log("test_rsa_generate", ATLOGGER_LOGGING_LEVEL_INFO, "D: ");
for (size_t i = 0; i < private_key.d.len; i++) {
printf("%02x ", private_key.d.value[i]);
}
printf("\n");
atlogger_log("test_rsa_generate", ATLOGGER_LOGGING_LEVEL_INFO, "P: ");
for (size_t i = 0; i < private_key.p.len; i++) {
printf("%02x ", private_key.p.value[i]);
}
printf("\n");
atlogger_log("test_rsa_generate", ATLOGGER_LOGGING_LEVEL_INFO, "Q: ");
for (size_t i = 0; i < private_key.q.len; i++) {
printf("%02x ", private_key.q.value[i]);
}
printf("\n");
} else {
atlogger_log("test_rsa_generate", ATLOGGER_LOGGING_LEVEL_ERROR, "Private key is not populated\n");
goto exit;
}
// use the public key to encrypt something
// use the private key to decrypt it
if((ret = atchops_rsa_encrypt(&public_key, (const unsigned char *)PLAINTEXT, strlen(PLAINTEXT), ciphertext)) != 0) {
atlogger_log("test_rsa_generate", ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to encrypt plaintext\n");
goto exit;
}
// log the ciphertext
atlogger_log("test_rsa_generate", ATLOGGER_LOGGING_LEVEL_INFO, "Ciphertext: ");
for (size_t i = 0; i < ciphertext_size; i++) {
printf("%02x ", ciphertext[i]);
}
size_t plaintext_len = 0;
if((ret = atchops_rsa_decrypt(&private_key, ciphertext, ciphertext_size, plaintext, plaintext_size, &plaintext_len)) != 0) {
atlogger_log("test_rsa_generate", ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to decrypt ciphertext\n");
goto exit;
}
// log the plaintext
atlogger_log("test_rsa_generate", ATLOGGER_LOGGING_LEVEL_INFO, "Plaintext: ");
for (size_t i = 0; i < plaintext_len; i++) {
printf("%c", plaintext[i]);
}
printf("\n");
// check if plaintext is equal to PLAINTEXT
if (strncmp((const char *)plaintext, PLAINTEXT, strlen(PLAINTEXT)) != 0) {
atlogger_log("test_rsa_generate", ATLOGGER_LOGGING_LEVEL_ERROR, "Plaintext does not match original\n");
goto exit;
} We
|
#closes #74
- What I did
- How to verify it
test_rsa_generate.c
that does two things: 1. generate a RSA key pair and populate our atchops structs successfully and 2. use the key to encrypt/decrypt and check if the plaintext matches- Description for the changelog
feat: atchops_rsa_generate